home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 August: Tool Chest / Dev.CD Aug 98 TC.toast / Tool Chest / Toolbox / Menu Defproc 1.0.3 / ChooseTkl.c next >
Encoding:
C/C++ Source or Header  |  1991-03-29  |  14.4 KB  |  396 lines  |  [TEXT/MPS ]

  1. /*============================================================================*\
  2. * ChooseTkl.c - mChooseMsg handler
  3. *
  4. * ChooseTkl.c contains just one enourmously long routine, DoChooseMsg.  This
  5. * routine handles the display of a menu after it's been pulled down or popped up
  6. * and before it's erased.
  7. \*============================================================================*/
  8.  
  9.  
  10. /******************************************************************************\
  11. * Header Files
  12. \******************************************************************************/
  13.  
  14. #include <Memory.h>
  15. #include <Menus.h>
  16. #include <Quickdraw.h>
  17. #include <Types.h>
  18. #include <Values.h>
  19. #include "ChooseTkl.h"
  20. #include "Concordia.h"
  21. #include "DrawTkl.h"
  22. #include "SizeTkl.h"
  23.  
  24.  
  25. /******************************************************************************\
  26. * Constants & Macros
  27. \******************************************************************************/
  28.  
  29. #define noScroll   ((short) 0) //Must not scroll
  30. #define upScroll   ((short) 1) //Must scroll up
  31. #define downScroll ((short) 2) //Must scroll down
  32.  
  33. /* System Globals */
  34. #define sgHuhRect     *((Rect *) 0x09FA)  //MenuSelect seems to need this
  35. #define sgMenuDisable *((long *) 0x0B54)  //MenuDisable system global (IM-V)
  36.  
  37.  
  38. /******************************************************************************\
  39. * Function Prototypes
  40. \******************************************************************************/
  41.  
  42. void RedrawItem (MenuHandle, short, Rect *, short);
  43.  
  44.  
  45. #pragma segment Main
  46. /******************************************************************************\
  47. * DoChooseMsg - Choose a menu item
  48. *
  49. * DoChooseMsg is an unbelievably long routine which processes the mChooseMsg
  50. * menu message for the menu specified by TheMenu.  DoChooseMsg will determine
  51. * which menu items must be hilighted and unhighlighted, and will highlight and
  52. * unhighlight those items appropriately.  If TheMenu has scroll arrows and the
  53. * location of the mouse (given in HitPt), is located in these scroll arrows,
  54. * DoChooseMsg will scroll the menu.  DoChooseMsg will then draw any newly-
  55. * exposed menu items.  When the end of TheMenu is reached while scrolling, the
  56. * scroll arrow at that end will be erased and the menu item behind it will be
  57. * drawn.  If a scrolling menu was at one end when it's scrolled, DoChooseMsg
  58. * will draw a new scroll arrow at that end.  The item number of the chosen item
  59. * is returned, or 0 if no item is chosen.
  60. *
  61. * Coding Notes
  62. * #A# - This loop calculates the item number and item rectangle of the item
  63. *       being chosen, the item rectangle of the item that was chosen the last
  64. *       time DoChooseMsg was called, and the sum of the heights of all of the
  65. *       items in TheMenu.  If no item is chosen or if the item is disabled, the
  66. *       item number will be calculated as 0.
  67. * #B# - Read as: If the vertical coordinate in the TopMenuItem system global
  68. *       doesn't coincide with the top of the menu rectangle, this menu has a top
  69. *       scroll arrow.
  70. * #C# - Read as: If the vertical coordinate in the AtMenuBottom system global
  71. *       doesn't coincide with the bottom of the menu rectangle, this menu has a
  72. *       bottom scroll arrow.
  73. * #D# - If the menu has a top or bottom scroll arrow, set the clipping region so
  74. *       that the scroll arrows won't be stomped on when items are hilighted and
  75. *       unhilighted.
  76. * #E# - If we're scrolling and there's no scroll bar at the other end, it must
  77. *       be drawn and the scroll rectangle adjusted for that.
  78. * #F# - If we've scrolled to an end of a menu, the scroll bar at that end must
  79. *       be drawn over.
  80. * #G# - This loop draws the menu items that intersect with UpdateRect.
  81. * #H# - If we saved the clip region, we'd better restore it.
  82. * #I# - Side Effect: System globals TopMenuItem and AtMenuBottom are modified
  83. *       here.  Icky, Poo!
  84. * #J# - Set high word of MenuDisable system global to menu ID, and low word to
  85. *       the item number.  Yes folks, even if the item is disabled.
  86. * #K# - If the item is disabled, its item number will be the 2's complement of
  87. *       whatever it should be.
  88. * #L# - Why do I have to do this?  BEATS THE HELL OUT OF ME!
  89. * #M# - Even if the new item isn't hierarchical, it might still get stomped on
  90. *       when a hierarchical menu is erased.
  91. * #N# - We don’t need the menuEnabled bit any more so get rid of it by shifting
  92. *       it out.  Then we have to set the high bit so that all items beyond the
  93. *       31st will be enabled.  With arithmetic right shifting, this high bit
  94. *       will be preserved.
  95. * #O# - If a hierarchical menu is up right at the top or bottom of the screen
  96. *       and the user moves the mouse into the scroll area of the main menu, we
  97. *       get a mChooseMsg with the hit point in the scroll area before the child
  98. *       menu is brought down.  That would cause DoChooseMsg to scroll the main
  99. *       menu while the child menu is still up.  Because the Menu Bar Definition
  100. *       Procedure saves the bits behind the child menu and because the child
  101. *       menu slightly overlaps the main menu, scrolling while the hierarchical
  102. *       menu is up causes a little bit of garbage to appear on the screen.  To
  103. *       prevent this, the DoDrawMsg routine clears a field in the MBSaveLoc
  104. *       record to 0.  DoChooseMsg checks this field.  If it’s set to 1, then
  105. *       scrolling is done as usual.  If it’s clear, then scrolling is supressed
  106. *       to give the menu bar definition procedure some time to bring down the
  107. *       hierarchical menu first.
  108. \******************************************************************************/
  109.  
  110. short
  111. DoChooseMsg (TheMenu, MenuRect, HitPt, WhichItem)
  112.     MenuHandle TheMenu;   //=> Menu to choose from >>
  113.     Rect       *MenuRect; //-> Menu's rectangle in global coords >>
  114.     Point      HitPt;     //Location of mouse in global coords >>
  115.     short      WhichItem; //Old chosen item >>
  116.     {
  117.     Str255        *ItemString; //-> Menu item's string
  118.     ItemInfoPtr   ItemInfo;    //-> Item info record
  119.     short         ItemHeight;  //Height of menu item in pixels
  120.     Rect          ItemRect;    //Item's rectangle in screen coords
  121.     short         TotHeight;   //Total height of menu in pixels
  122.     Rect          NewRect;     //Rectangle of newly-chosen item in global coords
  123.     short         NewItem;     //Item number of newly-chosen item
  124.     Rect          OldRect;     //Rectangle of old chosen item in global coords
  125.     short         OldItem;     //Item number of old chosen item
  126.     short         CurrItem;    //Item number of item being processed
  127.     short         NewIsHier;   //True if NewItem specifies hierarchical item
  128.     short         OldIsHier;   //True if OldItem specifies hierarchical item
  129.     short         HasTopScrl;  //True if menu has top scroll arrow
  130.     short         HasBotScrl;  //True if menu has bottom scroll arrow
  131.     short         MustScrl;    //Which direction must menu scroll, if any?
  132.     short         ScrollAmt;   //Scrolling distance in pixels
  133.     RgnHandle     SavedClip;   //=> Clip region before DoChooseMsg is called
  134.     Rect          MenuClip;    //Menu's clip rectangle, if scroll icons present
  135.     RgnHandle     UpdateRgn;   //=> Menu update region when scrolled
  136.     Rect          UpdateRect;  //Menu update rectangle when scrolled
  137.     long          EnableFlags; //Menu's enable flags
  138.     Boolean       dontScroll;  /* True if scrolling shouldn’t take place */
  139.  
  140.     EnableFlags = (unsigned long) (**TheMenu).enableFlags;
  141.     if (EnableFlags & 1)
  142.         {
  143.         EnableFlags >>= (unsigned long) 1; //#N#
  144.         EnableFlags |= 0x80000000;
  145.         }
  146.     else
  147.         EnableFlags = (unsigned long) 0;
  148.     SavedClip = (RgnHandle) null;
  149.     NewRect = OldRect = *MenuRect;
  150.     NewRect.top = NewRect.bottom = OldRect.top = OldRect.bottom = sgTopMenuItem;
  151.     NewItem = 0;
  152.     OldItem = 0;
  153.     CurrItem = 1;
  154.     TotHeight = 0;
  155.     NewIsHier = OldIsHier = false;
  156.     dontScroll = *((short *) ((*sgMBSaveLoc) + 16)) == 1; //#O#
  157.     if (dontScroll)
  158.         *((short *) ((*sgMBSaveLoc) + 16)) = 0;
  159.     HLock ((Handle) TheMenu);
  160.     ItemString = (Str255 *) (**TheMenu).menuData;
  161.     ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
  162.     while ((*ItemString) [0] != '\0') //#A#
  163.         {
  164.         ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize (*ItemString));
  165.         ItemHeight = CalcItemHeight (*ItemString, ItemInfo);
  166.         if (NewItem == 0)
  167.             {
  168.             NewRect.bottom = NewRect.top + ItemHeight;
  169.             if (HitPt.v > NewRect.top && HitPt.v <= NewRect.bottom)
  170.                 {
  171.                 if (EnableFlags & 1) //#K#
  172.                     NewItem = CurrItem;
  173.                 else
  174.                     NewItem = -CurrItem;
  175.                 if (ItemInfo->kbdEquiv == (char) hMenuCmd)
  176.                     NewIsHier = true;
  177.                 }
  178.             else
  179.                 NewRect.top += ItemHeight;
  180.             }
  181.         if (OldItem == 0)
  182.             if (WhichItem == CurrItem)
  183.                 {
  184.                 OldRect.bottom = OldRect.top + ItemHeight;
  185.                 OldItem = WhichItem;
  186.                 if (ItemInfo->kbdEquiv == (char) hMenuCmd)
  187.                     OldIsHier = true;
  188.                 }
  189.             else
  190.                 OldRect.top += ItemHeight;
  191.         TotHeight += ItemHeight;
  192.         CurrItem += 1;
  193.         ItemString = (Str255 *) (ItemInfo + 1);
  194.         EnableFlags >>= 1;
  195.         }
  196.     HUnlock ((Handle) TheMenu);
  197.     if (HitPt.h < MenuRect->left || HitPt.h > MenuRect->right)
  198.         NewItem = 0;
  199.     MustScrl = noScroll;
  200.     HasTopScrl = HasBotScrl = false;
  201.     if (sgTopMenuItem != MenuRect->top) //#B#
  202.         {
  203.         HasTopScrl = true;
  204.         if (HitPt.v < MenuRect->top + scrlIconHeight)
  205.             {
  206.             NewItem = 0;
  207.             MustScrl = downScroll;
  208.             }
  209.         }
  210.     if (sgAtMenuBottom != MenuRect->bottom) //#C#
  211.         {
  212.         HasBotScrl = true;
  213.         if (HitPt.v > MenuRect->bottom - scrlIconHeight)
  214.             {
  215.             NewItem = 0;
  216.             MustScrl = upScroll;
  217.             }
  218.         }
  219.     if (HasBotScrl || HasTopScrl) //#D#
  220.         {
  221.         MenuClip = *MenuRect;
  222.         if (HasBotScrl)
  223.             MenuClip.bottom -= scrlIconHeight;
  224.         if (HasTopScrl)
  225.             MenuClip.top += scrlIconHeight;
  226.         SavedClip = NewRgn ();
  227.         GetClip (SavedClip);
  228.         ClipRect (&MenuClip);
  229.         }
  230.     if (NewItem == 0)
  231.         sgMenuDisable = 0L;
  232.     else
  233.         {
  234.          sgMenuDisable = (**TheMenu).menuID << (BITS (long) / 2) | (NewItem > 0 ?
  235.                 NewItem : -NewItem); //#J# #K#
  236.         if (NewItem < 0)
  237.             NewItem = 0;
  238.         }
  239.     if (NewItem != 0 && NewIsHier) //#L#
  240.         {
  241.         sgHuhRect = NewRect;
  242.         *((Rect *) ((*sgMBSaveLoc) + 6)) = NewRect;
  243.         }
  244.     if (NewItem != OldItem)
  245.         {
  246.         if (OldItem != 0)
  247.             if (OldIsHier)
  248.                 RedrawItem (TheMenu, OldItem, &OldRect, false);
  249.             else
  250.                 InvertRect (&OldRect);
  251.         if (NewItem != 0)
  252.             if (OldIsHier) //#M#
  253.                 RedrawItem (TheMenu, NewItem, &NewRect, true);
  254.             else
  255.                 InvertRect (&NewRect);
  256.         }
  257.     if (!dontScroll && MustScrl && HitPt.h >= MenuRect->left && HitPt.h <=
  258.             MenuRect->right)
  259.         {
  260.         if (MustScrl == upScroll)
  261.             {
  262.             if (! HasTopScrl) //#E#
  263.                 {
  264.                 DrawScroll (MenuRect, topScroll);
  265.                 MenuClip.top += scrlIconHeight;
  266.                 }
  267.             ScrollAmt = MenuClip.bottom - HitPt.v;
  268.             if (ScrollAmt < MenuRect->bottom - sgAtMenuBottom)
  269.                 ScrollAmt = MenuRect->bottom - sgAtMenuBottom;
  270.             UpdateRgn = NewRgn ();
  271.             ScrollRect (&MenuClip, 0, ScrollAmt, UpdateRgn);
  272.             UpdateRect = (**UpdateRgn).rgnBBox;
  273.             DisposeRgn (UpdateRgn);
  274.             sgTopMenuItem += ScrollAmt; //#I#
  275.             sgAtMenuBottom += ScrollAmt;
  276.             if (sgAtMenuBottom == MenuRect->bottom) //#F#
  277.                 UpdateRect.bottom += scrlIconHeight;
  278.             if (SavedClip == (RgnHandle) null)
  279.                 {
  280.                 SavedClip = NewRgn ();
  281.                 GetClip (SavedClip);
  282.                 }
  283.             ClipRect (&UpdateRect);
  284.             EraseRect (&UpdateRect);
  285.             }
  286.         else
  287.             {
  288.             if (! HasBotScrl) //#E#
  289.                 {
  290.                 DrawScroll (MenuRect, botScroll);
  291.                 MenuClip.bottom -= scrlIconHeight;
  292.                 }
  293.             ScrollAmt = MenuClip.top - HitPt.v;
  294.             if (ScrollAmt > MenuRect->top - sgTopMenuItem)
  295.                 ScrollAmt = MenuRect->top - sgTopMenuItem;
  296.             UpdateRgn = NewRgn ();
  297.             ScrollRect (&MenuClip, 0, ScrollAmt, UpdateRgn);
  298.             UpdateRect = (**UpdateRgn).rgnBBox;
  299.             DisposeRgn (UpdateRgn);
  300.             sgTopMenuItem += ScrollAmt;
  301.             sgAtMenuBottom += ScrollAmt;
  302.             if (sgTopMenuItem == MenuRect->top) //#F#
  303.                 UpdateRect.top -= scrlIconHeight;
  304.             if (SavedClip == (RgnHandle) null)
  305.                 {
  306.                 SavedClip = NewRgn ();
  307.                 GetClip (SavedClip);
  308.                 }
  309.             ClipRect (&UpdateRect);
  310.             EraseRect (&UpdateRect);
  311.             }
  312.         SetRect (&ItemRect, MenuRect->left, sgTopMenuItem, MenuRect->right,
  313.                 sgTopMenuItem);
  314.         EnableFlags = (unsigned long) (**TheMenu).enableFlags;
  315.         if (EnableFlags & 1)
  316.             {
  317.             EnableFlags >>= (unsigned long) 1;
  318.             EnableFlags |= 0x80000000;
  319.             }
  320.         else
  321.             EnableFlags = (unsigned long) 0;
  322.         HLock ((Handle) TheMenu);
  323.         ItemString = (Str255 *) (**TheMenu).menuData;
  324.         ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
  325.         while ((*ItemString) [0] != '\0') //#G#
  326.             {
  327.             ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize
  328.                     (*ItemString));
  329.             ItemRect.bottom = ItemRect.top + CalcItemHeight (*ItemString,
  330.                     ItemInfo);
  331.             if (ItemRect.top < UpdateRect.bottom && ItemRect.bottom >
  332.                     UpdateRect.top)
  333.                 DrawItem (*ItemString, ItemInfo, &ItemRect, EnableFlags & 1);
  334.             EnableFlags >>= 1;
  335.             ItemRect.top = ItemRect.bottom;
  336.             ItemString = (Str255 *) (ItemInfo + 1);
  337.             }
  338.         HUnlock ((Handle) TheMenu);
  339.         }
  340.     if (SavedClip != (RgnHandle) null) //#H#
  341.         {
  342.         SetClip (SavedClip);
  343.         DisposeRgn (SavedClip);
  344.         }
  345.     return NewItem;
  346.     }
  347.  
  348.  
  349. #pragma segment Main
  350. /******************************************************************************\
  351. * RedrawItem - Redraw a menu item for hierarchical menus
  352. *
  353. * RedrawItem redraws a menu item that's been clobbered by a hierarchical menu.
  354. * The affected menu is specified by TheMenu.  The item number of the menu item
  355. * to redraw is given in ItemNum, while the item's rectangle is given in
  356. * ItemRect.  If the item is going to be selected, Select must be true so that
  357. * the item will be redrawn in inverse.  Otherwise Select must be false so that
  358. * the item will be redrawn normally.
  359. \******************************************************************************/
  360.  
  361. static void
  362. RedrawItem (TheMenu, ItemNum, ItemRect, Select)
  363.     MenuHandle TheMenu;   //=> Menu of life >>
  364.     short      ItemNum;   //Item number of item to redraw >>
  365.     Rect       *ItemRect; //Rectangle of item in screen coords >>
  366.     short      Select;    //True if item should be selected
  367.     {
  368.     Str255       *ItemString; //-> Menu item's string
  369.     ItemInfoPtr  ItemInfo;    //-> Item info record
  370.     short        CurrItem;    //Item number of item being checked
  371.     TextStateRec TextState;   //Current text modes, etc.
  372.  
  373.     CurrItem = 0;
  374.     HLock ((Handle) TheMenu);
  375.     ItemString = (Str255 *) (**TheMenu).menuData;
  376.     ItemString = (Str255 *) ((Byte *) ItemString + strSize (*ItemString));
  377.     while (ItemNum != CurrItem && (*ItemString) [0] != '\0')
  378.         {
  379.         ItemInfo = (ItemInfoPtr) ((Byte *) *ItemString + strSize
  380.                 (*ItemString));
  381.         CurrItem += 1;
  382.         if (ItemNum == CurrItem)
  383.             {
  384.             GetTextState (&TextState);
  385.             EraseRect (ItemRect);
  386.             DrawItem (*ItemString, ItemInfo, ItemRect, true);
  387.             if (Select)
  388.                 InvertRect (ItemRect);
  389.             SetTextState (&TextState);
  390.             }
  391.         else
  392.             ItemString = (Str255 *) (ItemInfo + 1);
  393.         }
  394.     HUnlock ((Handle) TheMenu);
  395.     }
  396.